// 拉取代码->编译->打包->上传镜像全部成功，并且镜像创建成功
pipeline {
    agent any

    tools {
        jdk 'jdk17'
        maven 'maven'
        dockerTool 'docker'
    }

    environment {
        GIT_REPO = 'https://gitee.com/zhouyadong1997/cloud-build.git'
        APP_NAME = 'cloud-build'
        WORKSPACE_DIR = "${WORKSPACE}"
        DOCKERFILE_PATH = "src/main/resources/docker/Dockerfile"
        // 阿里云相关配置
        ALIYUN_REGISTRY = "crpi-gdue2s806xzpkbep.cn-hangzhou.personal.cr.aliyuncs.com"
        REPO_NAMESPACE = "zyd123138"
        REPO_NAME = "cloud-build"
        DOCKER_USER = "周亚东zyd"
        DOCKER_PASSWORD = "294753618@zyd"
        // 构建配置
        BUILD_PROFILE = 'prod'
        // JVM 配置
        MAVEN_OPTS = '-Xmx1024m'
        // JAR 文件配置
        JAR_OUTPUT_DIR = "${WORKSPACE_DIR}/target"
        JAR_NAME = "${APP_NAME}-*.jar"
    }

    stages {
        stage('清理工作区') {
            steps {
                script {
                    echo "开始清理工作区..."
                    sh 'rm -rf *'
                    sh 'rm -rf .git'  // 彻底清除git历史

                    // 确认工作区已清空
                    echo "工作区清理后内容:"
                    sh "ls -al ${WORKSPACE_DIR}"
                    echo "工作区清理完成!"
                }
            }
        }

        stage('拉取代码') {
            steps {
                script {
                    echo "开始拉取代码..."
                    echo "代码仓库: ${GIT_REPO}"

                    // 拉取代码
                    git url: GIT_REPO, branch: 'master'

                    // 验证工作区目录
                    echo "Jenkins工作区根目录内容:"
                    sh "ls -al ${WORKSPACE_DIR}"

                    // 检查项目目录是否存在
                    def projectDir = "${WORKSPACE_DIR}/${APP_NAME}"
                    def projectDirExists = fileExists projectDir

                    if (projectDirExists) {
                        echo "项目目录存在: ${projectDir}"
                        sh "ls -al ${projectDir}"
                        env.BUILD_DIR = projectDir
                    } else {
                        echo "项目目录不存在，使用工作区根目录: ${WORKSPACE_DIR}"
                        env.BUILD_DIR = WORKSPACE_DIR
                    }

                    echo "代码拉取完成!"
                }
            }
        }

        stage('清除历史构建数据') {
            steps {
                script {
                    echo "开始清除历史构建数据..."

                    // 清除 target 目录
                    sh "rm -rf ${JAR_OUTPUT_DIR}"
                    sh "mkdir -p ${JAR_OUTPUT_DIR}"

                    echo "历史构建数据清除完成!"
                }
            }
        }

        stage('编译项目') {
            steps {
                script {
                    echo "开始编译项目..."
                    echo "构建目录: ${BUILD_DIR}"

                    // 检查是否存在 pom.xml 文件
                    def pomFile = "${BUILD_DIR}/pom.xml"
                    if (!fileExists(pomFile)) {
                        error "未找到 Maven 项目的 pom.xml 文件: ${pomFile}"
                    }

                    // 正确传递 MAVEN_OPTS 作为环境变量
                    def mavenCmd = "MAVEN_OPTS='${MAVEN_OPTS}' mvn clean package -Dmaven.test.skip=true"

                    // 检查 pom.xml 中是否存在 prod profile
                    if (fileExists(pomFile) && readFile(pomFile).contains("<id>prod</id>")) {
                        mavenCmd += " -P${BUILD_PROFILE}"
                        echo "激活 prod profile"
                    } else {
                        echo "未在 pom.xml 中找到 prod profile，继续构建不激活任何 profile"
                    }

                    // 执行 Maven 编译命令
                    sh mavenCmd

                    // 查找生成的 JAR 文件（优先使用非 .original 文件）
                    def mainJarFile = sh(script: "ls ${JAR_OUTPUT_DIR}/${JAR_NAME} 2>/dev/null || ls ${JAR_OUTPUT_DIR}/${JAR_NAME}.original 2>/dev/null || true", returnStdout: true).trim()
                    if (mainJarFile) {
                        env.MAIN_JAR_FILE = mainJarFile
                        echo "找到主 JAR 文件: ${mainJarFile}"
                    } else {
                        error "未找到生成的 JAR 文件: ${JAR_OUTPUT_DIR}/${JAR_NAME}"
                    }

                    // 使用相对于工作区根目录的路径归档 JAR 文件
                    archiveArtifacts artifacts: "target/${JAR_NAME}*", fingerprint: true

                    echo "项目编译完成!"
                }
            }
        }

        stage('验证 JAR 包可用性') {
            steps {
                script {
                    echo "开始验证 JAR 包可用性..."

                    // 创建临时目录用于测试
                    sh "mkdir -p ${WORKSPACE_DIR}/jar-test"

                    // 复制 JAR 文件到测试目录
                    sh "cp ${MAIN_JAR_FILE} ${WORKSPACE_DIR}/jar-test/app.jar"

                    // 尝试启动应用（超时机制，防止应用真正启动）
                    echo "尝试启动应用以验证 JAR 包有效性..."
                    try {
                        timeout(time: 30, unit: 'SECONDS') {
                            // 重定向输出到日志文件
                            sh "java -jar ${WORKSPACE_DIR}/jar-test/app.jar --spring.main.web-application-type=none --spring.profiles.active=test > ${WORKSPACE_DIR}/jar-test/startup.log 2>&1 &"

                            // 等待一段时间，检查应用是否正常启动
                            sleep 10

                            // 检查应用是否生成日志或其他标识文件
                            def logFile = "${WORKSPACE_DIR}/jar-test/startup.log"
                            if (fileExists(logFile)) {
                                def logContent = readFile(logFile)
                                echo "应用启动日志:"
                                echo logContent

                                if (logContent.contains("ERROR") || logContent.contains("Exception")) {
                                    echo "启动日志中发现错误"
                                    error "JAR 包启动过程中出现错误"
                                } else if (logContent.contains("Started")) {
                                    echo "JAR 包成功启动"
                                } else {
                                    echo "未检测到启动完成标志，可能应用启动失败"
                                    error "JAR 包未能成功启动"
                                }
                            } else {
                                echo "未找到应用日志文件，可能应用启动失败"

                                // 检查进程是否还在运行
                                def processCount = sh(script: "ps -ef | grep 'java -jar' | grep -v grep | wc -l", returnStdout: true).trim()
                                if (processCount == "0") {
                                    error "JAR 包未能成功启动"
                                } else {
                                    echo "JAR 包进程仍在运行，可能启动成功"
                                }
                            }
                        }
                    } catch (Exception e) {
                        // 捕获超时异常，这是预期行为
                        echo "JAR 包启动测试超时，视为启动成功"
                    } finally {
                        // 确保停止测试进程
                        sh "ps -ef | grep 'java -jar' | grep -v grep | awk '{print \$2}' | xargs -r kill -9 || true"
                        sh "rm -rf ${WORKSPACE_DIR}/jar-test"
                    }

                    echo "JAR 包可用性验证完成!"
                }
            }
        }

        stage('构建镜像') {
            steps {
                script {
                    echo "开始构建Docker镜像..."
                    echo "构建目录: ${BUILD_DIR}"

                    // 验证Dockerfile是否存在
                    def dockerfilePath = "${BUILD_DIR}/${DOCKERFILE_PATH}"
                    def dockerfileExists = fileExists dockerfilePath

                    if (!dockerfileExists) {
                        echo "指定路径的Dockerfile不存在: ${dockerfilePath}"
                        echo "尝试搜索项目中的Dockerfile文件..."

                        // 搜索整个项目中的Dockerfile
                        def foundDockerfiles = sh(script: "find ${BUILD_DIR} -name 'Dockerfile*'", returnStdout: true).trim()

                        if (foundDockerfiles) {
                            echo "找到以下Dockerfile文件:"
                            echo "${foundDockerfiles}"

                            // 使用第一个找到的Dockerfile
                            def firstDockerfile = foundDockerfiles.tokenize('\n')[0]
                            echo "将使用: ${firstDockerfile}"
                            env.DOCKERFILE_PATH = firstDockerfile
                        } else {
                            error "在项目中未找到任何Dockerfile文件!"
                        }
                    }

                    // 获取当前时间戳作为版本号
                    def version = sh(script: 'date +%Y%m%d%H%M%S', returnStdout: true).trim()
                    env.IMAGE_VERSION = version  // 保存到环境变量供后续阶段使用
                    def imageName = "${APP_NAME}:${version}"

                    // 使用找到的Dockerfile构建镜像
                    sh "docker build -f ${DOCKERFILE_PATH} -t ${imageName} ${BUILD_DIR}"

                    // 列出所有镜像，验证构建结果
                    sh 'docker images'

                    echo "Docker镜像构建完成!"
                    echo "镜像名称: ${imageName}"
                }
            }
        }

        stage('推送镜像到阿里云') {
            steps {
                script {
                    echo "开始登录阿里云Docker Registry..."
                    // 使用环境变量中的认证信息登录
                    sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD} ${ALIYUN_REGISTRY}"

                    // 从环境变量获取构建阶段生成的版本号
                    def remoteImageName = "${ALIYUN_REGISTRY}/${REPO_NAMESPACE}/${REPO_NAME}:${env.IMAGE_VERSION}"
                    def localImageName = "${APP_NAME}:${env.IMAGE_VERSION}"

                    // 重新标记镜像为阿里云路径
                    echo "重新标记镜像: ${localImageName} -> ${remoteImageName}"
                    sh "docker tag ${localImageName} ${remoteImageName}"

                    // 推送镜像到阿里云仓库
                    echo "开始推送镜像..."
                    sh "docker push ${remoteImageName}"
                    echo "镜像推送至阿里云完成!"
                }
            }
        }
    }

    post {
        success {
            echo "流水线执行成功!"
            echo "构建的JAR包: ${MAIN_JAR_FILE}"
            echo "Docker镜像版本: ${env.IMAGE_VERSION}"
            echo "镜像地址: ${ALIYUN_REGISTRY}/${REPO_NAMESPACE}/${REPO_NAME}:${env.IMAGE_VERSION}"
        }
        failure {
            echo "流水线执行失败!"
        }
        always {
            echo "流水线执行完毕!"
            // 清理工作
            sh "docker logout ${ALIYUN_REGISTRY} || true"

            // 只删除当前构建创建的镜像，而不是全部镜像
            sh "docker rmi -f ${APP_NAME}:${env.IMAGE_VERSION} ${ALIYUN_REGISTRY}/${REPO_NAMESPACE}/${REPO_NAME}:${env.IMAGE_VERSION} || true"
        }
    }
}